#ifndef BASIC_TYPES_H
#define BASIC_TYPES_H


#include <boost/preprocessor/repetition/for.hpp>
#include <boost/preprocessor/seq/subseq.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/control/expr_if.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/seq/pop_front.hpp>
#include <boost/preprocessor/seq/pop_back.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/facilities/empty.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/logical/not.hpp>
#include <boost/preprocessor/stringize.hpp>
#include "jncConvFn.h"
#include "jncTypeConversion.h"
#include "jncBaseMap.h"
#include "jncTemplates.h"
#include "jncInterface.h"
#include "jncImportNamespace.h"
#include "jncTypeInfo.h"
#include <iostream>

// This is to automaticly build objects that 
// represent the primitive types supported in C++


/* #define SEQTOELM(seq)       seq */
#define CLASSNAME(jtype)  BOOST_PP_CAT(C, jtype)
#define MEM_FNTNAME(jtype)   &CLASSNAME(jtype)::BOOST_PP_CAT(set_, jtype)

#define COND_CLASSEXPANSION(r, state)		\
  BOOST_PP_SEQ_SIZE(state)

#define MODIFY_STATE(r, state)			\
  BOOST_PP_SEQ_POP_FRONT(state)

#define POP(seq)   BOOST_PP_SEQ_HEAD(seq)

#define GETENUM(state)							\
  BOOST_PP_SEQ_ELEM(BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(BENUM), BOOST_PP_SEQ_SIZE(state)), BENUM)

#define GETLOCAL(state)							\
  BOOST_PP_SEQ_ELEM(BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_ELEM(BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(BLOCAL), BOOST_PP_SEQ_SIZE(state)), BLOCAL)), 1), BOOST_PP_SEQ_ELEM(BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(BLOCAL), BOOST_PP_SEQ_SIZE(state)), BLOCAL))

#define PRIMITIV_CLASS(r, state)					\
  BOOST_PP_EXPR_IF(BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_POP_FRONT(POP(state))), PRIMTEMPLATE(BOOST_PP_SEQ_ELEM(0, POP(state)), GETLOCAL(state), GETENUM(state), BOOST_PP_SEQ_ELEM(BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(POP(state)), 1), POP(state))))

#define PRIMITIVES							\
  BOOST_PP_FOR(BTRANSL, COND_CLASSEXPANSION, MODIFY_STATE, PRIMITIV_CLASS)

#define RTM_CONS(n, jtype)						\
  (exportObjectHandle<CLASSNAME(jtype)>(				\
					 new CLASSNAME(jtype)(),	\
					 (const char* [JINC_MAX_ARG]){BOOST_PP_STRINGIZE(jtype), "token", NULL}, \
					 (jncTypei [JINC_MAX_ARG]){JCMP, JCMP},	\
					 MEM_FNTNAME(jtype),		\
					 NORMAL				\
					 ))

#define GET_ELM(n, seq)   BOOST_PP_SEQ_ELEM(n, seq)
#define BUILD_RTM(r, data, t)						\
  BOOST_PP_EXPR_IF(BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(t), 1), RTM_CONS(n, BOOST_PP_SEQ_ELEM(0, t)))/* , ((NULL, NULL, NULL)))  */

/* #define APPEND_OBJ(r, data, t)						\ */
/*   (RtmInfo(BOOST_PP_TUPLE_ELEM(3, 0, t),BOOST_PP_TUPLE_ELEM(3, 1, t),BOOST_PP_TUPLE_ELEM(3, 2, t))) */
#define INIT_PRIMITIV_ARRAY						\
  BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(BUILD_RTM, ~, BTRANSL))

class CToken: public JncInterface {					\
  JNCINTERFACEIMPL(CToken, char*)					\
    public:								\
  gReturnCode BOOST_PP_CAT(set_, Token)(jncTypev b)			\
  {									\
    std::string tmp;							\
    try {								\
      tmp = jcmp<std::string>(b);					\
    }									\
    catch(boost::bad_any_cast& e)					\
      {									\
	std::string msg("Conversion from ");				\
	msg += std::string(std::string(getTypeName(b)) + " to ") + runtimeSymbol(); \
	throw RnException(ECONV, msg.c_str(), e);			\
      }									\
    return gReturnCode(new char*((char*)tmp.c_str()));			\
  }									\
};

extern RtmInfo primitiv_table[];

extern "C" {
  void getPrimitivesNamespace();
}

PRIMITIVES

#endif
